﻿using CentralFoveaLib.Brain;
using CentralFoveaLib.ColorProcess;
using CentralFoveaLib.Helper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    public class ImageHelper
    {
        public void ReadAllImage(String[] srcFilesPath, String tempPath, String outputFilePath)
        {

            foreach (String filePath in srcFilesPath)
            {
                String tempFilePath = Path.Combine(tempPath, Path.GetFileName(filePath));
                String ext = Path.GetExtension(tempFilePath).ToLower();
                if (ext == ".jpg" || ext == ".png")
                {
                    File.Copy(filePath, tempFilePath, true);//将源文件Copy过来
                    this.LoadImage2(tempFilePath, outputFilePath);
                }
            }
        }

        public void LoadImage2(String fullSrcPath, String targetPath, String fileType = ".png")
        {

            String fileName = Path.GetFileNameWithoutExtension(fullSrcPath);
            String outputDirectory = Path.Combine(targetPath, fileName);
            Image imgThum = Thumbnail.MakeThumbnail(fullSrcPath, 64, 64, "HW");
            List<CCell> cells = GetCells(new Bitmap(imgThum));
            SaveBitmapToPix(outputDirectory, fileName + ".txt", cells, 6, true);
        }

        public void LoadImage(String fullSrcPath, String targetPath, String fileType = ".png")
        {
            ImageFormat imgFormat = ImageFormat.Jpeg;

            String fileName = Path.GetFileNameWithoutExtension(fullSrcPath);
            //取得文件的输出目录,创建文件的输出目录
            String outputDirectory = Path.Combine(targetPath, fileName);
            if (!File.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); }


            //缩略图为512*512
            //生成缩略图
            String fileNameExt = fileName + PathHelper.SNAIL_512_PATH + fileType;
            String outputFullName = Path.Combine(outputDirectory, fileNameExt);
            Image imgThum = Thumbnail.MakeThumbnail(fullSrcPath, 512, 512, "HW");
            imgThum.Save(outputFullName, imgFormat);


            #region
            //将文件转换为视觉细胞
            //List<CCell> cells = GetCells(new Bitmap(imgThum));

            /*
            //根据容差得到边缘

            //得到像素块
            //根据颜色的色差将颜色分组
            IDictionary<int, List<CCell>> dict = CellHelper.GetGroup(cells);

            foreach (var item in dict)
            {
                SaveBitmapToPix(Path.Combine(outputDirectory, "Color"), item.Key + ".txt", item.Value, 6, true);
            }

            dict = CellHelper.GetGrayGroup(cells);

            var faces = GetHistogram(Path.Combine(outputDirectory, "his.txt"), dict);
            String cellFileName = fileName + PathHelper.CELL_PATH + fileType;
            String cellFileFullName = Path.Combine(outputDirectory, cellFileName);

            Bitmap bitmapCell = DrawCells(dict, new Bitmap(imgThum), faces);
            bitmapCell.Save(cellFileFullName, imgFormat);
            */

            //根据颜色的直方图将颜色分块
            //取得直方图 0 为绝对断电,相对断点
            //将颜色分块，分到最细粒度

            //灰化 根据512px缩略图进行灰化 512px-Gray
            /*Bitmap bitmapGray = Gray(new Bitmap(imgThum));
            // Bitmap bitmapGray = Thumbnail.Gray(new Bitmap(fullSrcPath));
            String grayFileName = fileName + PathHelper.GRAY_PATH + fileType;
            String grayFileFullName = Path.Combine(outputDirectory, grayFileName);
            bitmapGray.Save(grayFileFullName, imgFormat);


            List<CCell> cellsGray = GetCells(bitmapGray);
            */

            //根据容差得到边缘

            //得到像素块
            //根据颜色的色差将颜色分组
            /*
            IDictionary<int, List<CCell>> dictGray = CellHelper.GetGroup(cellsGray);
            foreach (var item in dictGray)
            {
                SaveBitmapToPix(Path.Combine(outputDirectory, "Gray"), item.Key + ".txt", item.Value, 6, true);
            }
            */

            //物理层将图像转换为单元,以最近9个像素为单元
            /*for (int i = 0; i < cellsGray.Count; i++)
            {
                var cCell = cellsGray[i];
                if ((i + 1) % 9 == 0)
                {
                    
                }
            }*/

            ////二值化图像
            //List<CCell> pCells = CellHelper.PGroup(cells);
            //var factory = new CellFactory();
            //var cellSet = factory.BuildCellSet(5);
            ////将图像输入进入单元
            //Input(pCells, cellSet);
            //cellSet.Learning(0);
            #endregion
            var cells2 = GetMatrix(new Bitmap(imgThum));
            #region 
            //MoveResult focusCell = Move(cells2, (int)(cells2.Length / 2), (int)(cells2.Length / 2), 64);
            //得到百分比。然后去比较以前是否有这样的东西
            //给它提供 左上右下，放大，缩小的操作。
            //以及合并的操作
            //学习，就是将之前没有的记录下来，1要记录他的操作，2要记录学习到的内容
            //如何判断学习到？就是在同等的level下只有一个图案
            /*
            Random random = new Random();
            List<Cell> list = new List<Cell>();
            //Cell cell = null;
            IDictionary<String, String> dict = new Dictionary<String, String>(1024 * 1024);
            for (int i = 0; i < 1000; i++)
            //while (true)
            {
                int x = random.Next(0, 512);
                int y = random.Next(0, 512);
                int level = random.Next(0, 64);
                String key = String.Format("{0},{1},{2}", x, y, level);
                if (dict.ContainsKey(key))
                {
                    continue;
                }
                else
                {
                    dict[key] = key;
                }
                var isBlock = IsArea(cells2, x, y, level);
                if (isBlock.CanMove && isBlock.Central !=null)
                {
                    Console.WriteLine("{0},{1},{2}", x, y, level);
                    Cell cell = isBlock.Central;
                    list.Add(cell);
                    //break;
                }
            }

            if (list.Count>0)
            {
                var img = Cut(new Bitmap(imgThum),Combine( list));
                String fileNameCut = fileName + "_cc" + fileType;
                String outputFullNameCut = Path.Combine(outputDirectory, fileNameCut);

                img.Save(outputFullNameCut, imgFormat);
            }*/
            #endregion
            
            //根据CCell创建NCell
            var nnCell = new TestCells();
            var nnCellList = nnCell.BuildInputCell(cells2);
            //var newCells = nnCell.BuildCellTemplateByCell(nnCellList);
            //找出符合上一层的Cell,然后连接上

            Console.WriteLine("Find Image");
            Console.ReadKey();
        }

        private Cell Combine(List<Cell> list)
        {
            Cell cell = list[0];
            for (int i = 1; i < list.Count; i++)
            {
                var item = list[i];
                cell.AddCell(item);
            }
            return cell;
        }

        private Bitmap Cut(Bitmap srcBitmap, Cell cell)
        {

            if (srcBitmap != null)
            {
                Bitmap temp = new Bitmap(cell.XAxis.Length, cell.YAxis.Length);

                //cell.Print();
                int tx = cell.X;
                int ty = cell.Y;
                
                for (int i = 0; i < cell.YAxis.Length; i++)
                {
                    for (int j = 0; j < cell.XAxis.Length; j++)
                    {
                        temp.SetPixel(j, i, srcBitmap.GetPixel(tx + j, ty + i));
                    }
                }
                return temp;
            }
            return null;
        }


        public MoveResult IsArea(CCell[][] cells, int x, int y, int level)
        {
            MoveResult result = new MoveResult();
            if (level > 64)
            {
                return result;
            }
            MoveResult focusCell = Search(cells, x, y, level + 1);
            if (focusCell.CanMove)
            {
                Cell cell = focusCell.Central;

                if (cell !=null && cell.IsBlock())
                {
                    focusCell.Central = cell.Compress();
                    return focusCell;
                }
            }
            return result;
        }




        /// <summary>
        /// 将输入的图像转换进入第一级神经元
        /// </summary>
        /// <param name="cells"></param>
        /// <param name="cellSet"></param>
        private void Input(List<CCell> cells, CellSet cellSet)
        {
            var inputLayer = cellSet.AixCells[0];
            int level = (int)(512 / 16);
            Histogram[][] hist = new Histogram[level][];
            for (int i = 0; i < level; i++)
            {
                hist[i] = new Histogram[level];
            }
            #region
            for (int i = 0; i < cells.Count; i++)
            {
                CCell cell = cells[i];
                int xt = (int)(cell.X / 16);
                int yt = (int)(cell.Y / 16);

                var hisItem = hist[yt][xt];
                if (hisItem == null)
                {
                    hisItem = new Histogram(16, 16);
                    hist[yt][xt] = hisItem;
                }
                if (cell.L)
                {
                    int x = (int)(cell.X - xt * 16);
                    int y = (int)(cell.Y - yt * 16);
                    hisItem.XAxis[x] += 1;
                    hisItem.YAxis[y] += 1;
                }
            }
            #endregion
            for (int i = 0; i < level; i++)
            {
                for (int j = 0; j < level; j++)
                {
                    var hisItem = hist[i][j];
                    if (hisItem == null) break;
                    var xAxis = hisItem.XAxis;
                    var yAxis = hisItem.YAxis;
                    Cell cell = CellHelper.GetCell(inputLayer, j, i);
                    cell.XAxis = xAxis;
                    cell.YAxis = yAxis;
                    //cell.OutputX = xAxis;
                    //cell.OutputY = yAxis;
                }
            }
        }

        public static IDictionary<int, Face> GetHistogram(String fileFullName, IDictionary<int, List<CCell>> dictGray)
        {
            IDictionary<int, int> z = new Dictionary<int, int>();

            IDictionary<int, Face> faceList = new SortedDictionary<int, Face>();
            List<String> list = new List<string>();
            int max = 0;
            foreach (var dictItem in dictGray)
            {
                List<CCell> cells = dictItem.Value;
                int[] x = new int[512];
                int[] y = new int[512];
                var xy = new Histogram(0, 0);
                //var xz = new Histogram();
                foreach (var item in cells)
                {
                    int xIndex = Convert.ToInt32(item.X);
                    int yIndex = Convert.ToInt32(item.Y);
                    x[xIndex] += 1;
                    y[yIndex] += 1;
                }

                xy.XAxis = x;
                xy.YAxis = y;
                //  z[dictItem.Key] = dictGray.Count;
                //  z.Insert(dictItem.Key, cells.Count);
                if (cells.Count > max) { max = cells.Count; }
                faceList[dictItem.Key] = new Face() { his = xy, ZAxis = cells.Count, cell = cells.First() };
            }
            foreach (var item in faceList)
            {
                int l = (int)(item.Value.ZAxis * 100 / max);
                //Console.Write(new char[l]);
                //Console.WriteLine(item.Value.ZAxis);
                var rgb = item.Value.cell.RGB;
                list.Add(new String(new char[l]) + item.Value.ZAxis + String.Format(" {0},{1},{2}", rgb.R, rgb.G, rgb.B));

            }
            File.WriteAllLines(fileFullName, list.ToArray());
            return faceList;
        }

        /// <summary>
        /// 灰化
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <returns></returns>
        public static List<CCell> GetCells(Bitmap srcBitmap)
        {
            List<CCell> list = new List<CCell>();
            if (srcBitmap != null)
            {
                list = new List<CCell>(srcBitmap.Width * srcBitmap.Height);
                Bitmap curBitmap = srcBitmap.Clone() as Bitmap;
                Color curColor;

                for (int i = 0; i < curBitmap.Width; i++)
                {
                    for (int j = 0; j < curBitmap.Height; j++)
                    {
                        curColor = curBitmap.GetPixel(i, j);
                        var rgb = new ColorRGB(curColor.R, curColor.G, curColor.B);
                        list.Add(new CCell()
                        {
                            X = i,
                            Y = j,
                            RGB = rgb,
                            HSL = ColorUtils.RGB_HSL(rgb),
                            Gray = ColorUtils.GetGray(rgb)
                        });
                    }
                }
            }
            return list;
        }


        public static CCell[][] GetMatrix(Bitmap srcBitmap)
        {
            if (srcBitmap != null)
            {
                int row = srcBitmap.Height;
                int col = srcBitmap.Width;
                CCell[][] cells = new CCell[row][];
                Bitmap curBitmap = srcBitmap.Clone() as Bitmap;
                Color curColor;

                for (int j = 0; j < curBitmap.Height; j++)
                {
                    cells[j] = new CCell[curBitmap.Width];

                    for (int i = 0; i < curBitmap.Width; i++)
                    {
                        curColor = curBitmap.GetPixel(i, j);
                        var rgb = new ColorRGB(curColor.R, curColor.G, curColor.B);
                        cells[j][i] = new CCell()
                        {
                            X = i,
                            Y = j,
                            RGB = rgb,
                            HSL = ColorUtils.RGB_HSL(rgb),
                            Gray = ColorUtils.GetGray(rgb)
                        };
                    }
                }

                return cells;
            }
            return new CCell[0][];
        }

        //
        public static void SplitMatrix(CCell[][] cells, int level)
        {

            for (int i = 0; i < level; i++)
            {

            }
        }


        public static Cell GetTile(CCell[][] cells, int x, int y, int level)
        {
            int count = level * 2;
            Cell cell = new Cell();
            cell.XAxis = new int[count];
            cell.YAxis = new int[count];

            int tx = x - level;
            int ty = y - level;
            cell.X = tx;
            cell.Y = ty;
            bool find = false;
            for (int j = 0; j < count; j++)
            {
                for (int i = 0; i < count; i++)
                {
                    var gray = cells[ty + j][tx + i].Gray;
                    xx[gray.ToString()] = gray.ToString();
                    if (gray < 250)
                    {
                        cell.YAxis[j] += 1;
                        cell.XAxis[i] += 1;
                        find = true;
                    }
                }
            }
            if (find)
                return cell;
            else
                return null;
        }

        private static IDictionary<String, String> xx = new Dictionary<String, String>();


        public static MoveResult Search(CCell[][] cells, int x, int y, int level)
        {
            var result = new MoveResult();
            if (y - level > 0)
            {
                result.CanMoveTop = true;
            }

            if (y + level < cells.Length)
            {
                result.CanMoveBottom = true;
            }
            if (x - level > 0)
            {
                result.CanMoveLeft = true;
            }

            if (x + level < cells[0].Length)
            {
                result.CanMoveRight = true;
            }

            if (result.CanMove)
            {
                var cell =  GetTile(cells, x, y, level);
                if (cell!=null)
                {
                    result.Central = cell;
                }
            }

            return result;
        }

        /// <summary>
        /// 灰化
        /// </summary>
        /// <param name="srcBitmap"></param>
        /// <returns></returns>
        public static Bitmap Gray(Bitmap srcBitmap)
        {
            if (srcBitmap != null)
            {
                Bitmap curBitmap = srcBitmap.Clone() as Bitmap;
                Color curColor;
                int ret;
                for (int i = 0; i < curBitmap.Width; i++)
                {
                    for (int j = 0; j < curBitmap.Height; j++)
                    {
                        curColor = curBitmap.GetPixel(i, j);
                        ret = (int)(curColor.R * 0.299 + curColor.G * 0.587 + curColor.B * 0.114);
                        curBitmap.SetPixel(i, j, Color.FromArgb(ret, ret, ret));
                    }
                }
                return curBitmap;
            }
            return null;
        }// end for class

        public static Bitmap DrawCells(IDictionary<int, List<CCell>> dictGray, Bitmap srcBitmap, IDictionary<int, Face> faces)
        {
            if (srcBitmap != null)
            {
                Bitmap curBitmap = new Bitmap(srcBitmap.Width, srcBitmap.Height);
                IDictionary<int, int> keyList = new Dictionary<int, int>();
                SortedDictionary<int, int> tempKeyList = new SortedDictionary<int, int>();

                foreach (var item in faces)
                {
                    tempKeyList[item.Value.ZAxis] = item.Key;
                }

                var keys = tempKeyList.Keys.ToArray();

                int flag = keys.Length;//(int)(keys.Length * (1 - 0.618))

                for (int i = keys.Length - 1, k = 0; k < flag && i > 0; i--, k++)
                {
                    var key = keys[i];
                    keyList[tempKeyList[key]] = tempKeyList[key];
                }
                //  int ret = 100;
                Random v = new Random(new DateTime().Second);
                foreach (var item in dictGray)
                {
                    if (keyList.Count >= 0 && !keyList.ContainsKey(item.Key)) continue;
                    int r = v.Next(0, 256);
                    int g = v.Next(0, 256);
                    int b = v.Next(0, 256);
                    foreach (var cell in item.Value)
                    {
                        var color = ColorUtils.HSL_RGB(cell.HSL);
                        int ret = ColorUtils.GetEGray(color);
                        curBitmap.SetPixel((int)cell.X, (int)cell.Y, Color.FromArgb(r, g, b));//color.R, color.G, color.B
                    }
                    //ret += 5;
                }
                return curBitmap;
            }
            return null;
        }

        private void SaveBitmapToPix(String path, String name, List<CCell> cells, int flag, bool isLock)
        {

            if (!Directory.Exists(path)) { Directory.CreateDirectory(path); }
            String fileFullName = Path.Combine(path, name);
            int ret;
            List<String> list = new List<String>(cells.Count);
            for (int i = 0; i < cells.Count; i++)
            {

                CCell c = cells[i];
                ret = (int)c.Gray;
                //if ((ret == 0 || ret == 255) && isLock) continue;
                StringBuilder build = new StringBuilder(6);
                // x,y,z r,g,b
                if (flag == 3)
                {
                    build.Append(ret);
                    build.Append(";");
                    list.Add(build.ToString());
                }
                else if (flag == 6)
                {

                    build.Append(c);
                    build.Append(";");
                    list.Add(build.ToString());
                }
            }
            File.WriteAllLines(fileFullName, list.ToArray());

        }

    }//end for class
    public class Histogram
    {
        public Histogram(int x, int y) { this.XAxis = new int[x]; this.YAxis = new int[y]; }
        public int[] XAxis { get; set; }
        public int[] YAxis { get; set; }
    }

    public class Face
    {
        public int ZAxis { get; set; }
        public Histogram his { get; set; }
        public CCell cell { get; set; }
    }
    public class CPoint
    {
        public int X { get; set; }
        public int Y { get; set; }
    }

    public class MoveResult
    {
        public Cell Central { get; set; }
        public bool CanMove
        {
            get
            {
                return CanMoveTop && CanMoveBottom && CanMoveLeft && CanMoveRight;
            }
        }
        public bool CanMoveTop { get; set; }
        public bool CanMoveBottom { get; set; }
        public bool CanMoveLeft { get; set; }
        public bool CanMoveRight { get; set; }
    }
}
